<?php
  require_once('connections.php');
//require_once('C:\wamp\www\si\nuevo\connections.php');

class Fachada {

  // -- FUNCIONES AUXILIARES --------------------------------------------
  public static function class_to_table($name) {
    /*
     Transforma un nombre de clase a un nombre de
     tabla, segun las convenciones tomadas.
    */
    $nombreT = $name[0];
    for ($i = 1; $i < strlen($name); $i++) {
      if (preg_match('/[A-Z]/', $name[$i])) {
	$nombreT = $nombreT . "_" . $name[$i];
      }
      else {
	$nombreT = $nombreT . $name[$i];
      }
    }
    return strtoupper($nombreT);
  }

  public static function table_to_class($name) {
    /*
     Transforma un nombre de tabla a un nombre de
     clase, segun las convenciones tomadas
    */
    $nombreC = $name[0];
    for ($i = 1; $i < strlen($name); $i++) {
      if (!strcmp($name[$i], "_") == 0) {
	$nombreC = $nombreC . strtolower($name[$i]);
      }
      else {
	$i++;
	$nombreC = $nombreC . $name[$i];
      }
    }
    return $nombreC;
  }

  private static function doQuery($query, $class_name = '') {
    /*
      Hace el proceso de ejecutar un query y devolver cualquiera de los
      tres tipos de resultado.

      El proceso de ejecutar un query basicamente es:
      0. Crear un manager
      1. El manager abre una conexion
      2. Crear un cursor para esa conexion.
      3. Usar el cursor para ejecutar el query y obtener el resultado
      4. Cerrar la conexion abierta.

      Este metodo es basicamente un shortcut para no estar teniendo que
      repetir codigo.
     */
    $man = new dbManager();
    $man->conectar();
    $cursor = $man->crearCursor();

    $query = trim($query); // strip whitespaces...

    $cursor->execute($query);

    $rset = True;
    /*
      Verificamos que la consulta no sea un insert, update o delete, porque
      de ser asi, no se devuelve ningun result_set.
      MEJORAR
     */
    if (stripos($query, "insert") === False && stripos($query, "update") === False
	&& stripos($query, "delete") === False) {

      if ($cursor->count() > 0)
	$rset = $cursor->fetchAllInArray($class_name);
      else
	$rset = False;
    }

    // Cerramos la conexion
    $man->desconectar();

    return $rset;
  }


  //------------------------------------------------------------------------------

  /*
    METODOS PARA INSTANCIAS/OBJETOS
   */

  public function insertarObjeto($table_name, $obj) {
    /*
      Inserta un objeto $obj en la base de datos. Construye el query con los
      argumentos del objeto (ver doc del metodo getAttrs) y lo ejecuta.

      To-Do: Verificar que el query este bien creado, proteger contra
      SQL Injection
     */
    $atributos = $obj->getAttrs();

    // Construimos la sentencia de insertar
    $attrs = "";
    $values = "";
    foreach ($atributos as $nomb => $valor)
      $attrs .= "".$nomb.",";
    foreach ($atributos as $nomb => $valor)
      $values .= "'".$valor."',";

    $attrs = substr($attrs, 0, -1);
    $values = substr($values, 0, -1);

    $query = "INSERT INTO " . $table_name . " (".$attrs.") VALUES (".$values.")";

    self::doQuery($query,self::table_to_class($table_name));

    // Buscamos el id asignado en la base de datos y se lo colocamos
    // en el atributo id del objeto. Esto sirve como un flag para decir
    // que el objeto ya fue agregado a la base de datos. (ineficiente)
    $obj->id = $obj->getID();
    return $obj;
  }

  public static function actualizarObjeto($table_name, $obj) {
    $atributos = $obj->getAttrs();

    // Construimos la sentencia de updatear
    $changes = "";
    foreach ($atributos as $nomb => $valor)
    $changes .= $nomb . '= "' . $valor . '", ';
    $changes = substr($changes, 0, -2);
    $query = "UPDATE " . $table_name . " SET " . $changes . " WHERE id = " . $obj->id;

    // Updateamos el objeto
    self::doQuery($query,self::table_to_class($table_name));
    return $obj;
  }

  public static function borrarObjeto($table_name, $obj) {
    $query = sprintf("DELETE FROM %s WHERE id = %s", $table_name, $obj->id);
    return self::doQuery($query,self::table_to_class($table_name));
  }


  /*
    METODOS PARA FILTRAR BUSQUEDAS DE OBJETOS
   */
  public static function obtenerObjeto($table_name, $obj_id) {
    $query = sprintf("SELECT * FROM %s WHERE id = %s", $table_name, $obj_id);
    return self::doQuery($query, self::table_to_class($table_name));
  }

  public static function obtenerObjetoComo($table_name, $obj_field, $search_term) {
    /*
      Busca sobre una tabla 'table_name' con el operador LIKE, ejemplo
      select * from $table_name where $obj_field LIKE $search_term
     */

    $query = sprintf("SELECT * FROM %s WHERE %s LIKE %s", $table_name, $obj_field, $search_term);
    return self::doQuery($query, self::table_to_class($table_name));
  }

  public static function obtenerObjetoEstricto($table_name, $obj_field, $search_term) {

    $query = sprintf("SELECT * FROM %s WHERE %s = '%s'", $table_name, $obj_field, $search_term);
    return self::doQuery($query, self::table_to_class($table_name));
  }

    public static function obtenerObjetoEstrictoPorCampos($table_name, $fields) {
	$query = "SELECT * FROM $table_name WHERE ";
	foreach ($fields as $obj_field => $search_term)
		$query .= "$obj_field = $search_term AND ";
	$query = substr($query, 0, -4);

	return self::doQuery($query, self::table_to_class($table_name));
    }

  public static function obtenerUltimo($table_name, $datetime_field) {
    /*
      Obtiene la 'ultima' tupla obtenida segun un orden por el campo de
      $datetime_field.
      Un ejemplo de llamada a este metodo seria:
      Fachada::obtenerUltimo('tablatura', 'dia_modificado')
     */

    $query = sprintf("SELECT * FROM %s ORDER BY %s DESC", $table_name, $datetime_field);

    // Aqui, intensionalmente, voy a NO usar doQuery porque no queremos
    // obtener todos los resultados, sino �nicamente el mas reciente.
    $man = new dbManager();
    $man->conectar();
    $cursor = $man->crearCursor();

    $cursor->execute($query);
    $obj = $cursor->fetchOne(self::table_to_class($table_name));

    $man->desconectar();
    return $obj;
  }


  /*
    METODOS PARA OBTENER RESULTSETS EN UNA CLASE/TABLA

    TO-DO GENERAL: Asegurarse de protegerse contra el SQL Injection.
   */
  public static function obtenerTodos($table_name) {
    /*
      Obtiene absolutamente todas las instancias de una
      clase/tabla
     */
    $query = sprintf("SELECT * FROM %s", $table_name);
    return self::doQuery($query, self::table_to_class($table_name));
  }

  public static function obtenerOrdenados($table_name, $order_field, $asc = False, $int=False) {
    /*
      Obtiene todas las instancias de las clase/tabla $tablename
      ordenadas por el campo $order_field. El ejemplo seria similar
      al de obtenerUltimo.
      En caso de querer utilizar el metodo para interrelaciones, se
      deben pasar ambos argumentos booleanos asc e int.
     */
    $query = sprintf("SELECT * FROM %s ORDER BY %s", $table_name, $order_field);
    if ($asc)
      $query .= " ASC";
    else
      $query .= " DESC";
    if($int)
      $table_name = '';

    return self::doQuery($query, self::table_to_class($table_name));
  }

  public static function obtenerOrdenadosDonde($table_name, $order_field, $where_field, $asc = True, $int=False) {
    /*
      Obtiene todas las instancias de las clase/tabla $tablename
      ordenadas por el campo $order_field. El ejemplo seria similar
      al de obtenerUltimo.
      En caso de querer utilizar el metodo para interrelaciones, se
      deben pasar ambos argumentos booleanos asc e int.
     */
    $query = sprintf("SELECT * FROM %s WHERE %s ORDER BY %s", $table_name, $where_field ,$order_field);
    if ($asc)
      $query .= " ASC";
    else
      $query .= " DESC";
     if($int)
      $table_name = '';
    return self::doQuery($query, self::table_to_class($table_name));
  }

  //Busqueda Modelo

      public static function BusquedaModelo($bus, $table_name, $id){
          $query = "SELECT * FROM ".$table_name." WHERE id = ".$id." and (`codigo` LIKE '%".$bus."%' or `nombre` LIKE '%".$bus."%')";
          return self::doQuery($query, self::table_to_class($table_name));
      }

  //Busqueda
      public static function BusquedaSaoa($bus,$tabla,$rangoI=0,$rangoF=50){
        if($tabla=="USUARIO"){
            $query=sprintf("SELECT *,MATCH(`apodo`,`nombre`,`apellido`,`correo`,`departamento`) AGAINST ( '%s' IN BOOLEAN MODE) AS puntuacion FROM USUARIO WHERE MATCH(`apodo`,`nombre`,`apellido`,`correo`,`departamento`) AGAINST ( '%s' IN BOOLEAN MODE) ORDER BY puntuacion DESC limit %d,%d",$bus,$bus,$rangoI, $rangoF);
        } elseif ($tabla=="ASIGNATURA") {
           $query=sprintf("SELECT *,MATCH(`nombre`, `codigo`, `descripcion`,`requerimientoAul`,`departamento`) AGAINST ( '%s' IN BOOLEAN MODE) AS puntuacion FROM ASIGNATURA WHERE MATCH(`nombre`, `codigo`, `descripcion`,`requerimientoAul`,`departamento`) AGAINST ( '%s' IN BOOLEAN MODE) ORDER BY puntuacion DESC limit %d,%d",$bus,$bus,$rangoI, $rangoF);
        } elseif ($tabla=="OFERTAR") {
            $query=sprintf("SELECT DISTINCT OFERTAR.*, ((MATCH( OFERTAR.profesor) AGAINST ('%s' IN BOOLEAN MODE))+(MATCH(BLOQUE.nombre) AGAINST ('%s'IN BOOLEAN MODE))+(MATCH(ASIGNATURA.nombre, ASIGNATURA.codigo, ASIGNATURA.descripcion, ASIGNATURA.requerimientoAul, ASIGNATURA.departamento) AGAINST ('%s'IN BOOLEAN MODE))) AS puntuacion FROM (OFERTAR JOIN BLOQUE ON (OFERTAR.idBloque=BLOQUE.id) ) JOIN ASIGNATURA ON (BLOQUE.idAsignatura=ASIGNATURA.ID) WHERE (MATCH(OFERTAR.profesor) AGAINST ('%s' IN BOOLEAN MODE) or MATCH(BLOQUE.nombre) AGAINST ('%s'IN BOOLEAN MODE) or MATCH(ASIGNATURA.nombre, ASIGNATURA.codigo, ASIGNATURA.descripcion, ASIGNATURA.requerimientoAul, ASIGNATURA.departamento) AGAINST ('%s'IN BOOLEAN MODE)) ORDER BY puntuacion DESC  limit 0,20  ",$bus,$bus,$bus,$bus,$bus,$bus);
        }
        return self::doQuery($query,"");
    }

      public static function BusquedaSaoa2($bus,$tabla,$rangoI=0,$rangoF=50){
        if($tabla=="USUARIO"){
            $query="SELECT * FROM USUARIO WHERE `apodo` LIKE '%".$bus."%' or `nombre` LIKE '%".$bus."%' or `apellido` LIKE '%".$bus."%' or `correo` LIKE '%".$bus."%' or `departamento` LIKE '%".$bus."%' limit ".$rangoI.",".$rangoF;
        } elseif ($tabla=="ASIGNATURA") {
            $query="SELECT * FROM ASIGNATURA WHERE `nombre` LIKE '%".$bus."%' or `codigo` LIKE '%".$bus."%' or `descripcion` LIKE '%".$bus."%' limit ".$rangoI.",".$rangoF;
        } elseif ($tabla=="OFERTAR") {
            $query=sprintf("SELECT DISTINCT OFERTAR.*, ((MATCH( OFERTAR.profesor) AGAINST ('%s' IN BOOLEAN MODE))+(MATCH(BLOQUE.nombre) AGAINST ('%s'IN BOOLEAN MODE))+(MATCH(ASIGNATURA.codigo, ASIGNATURA.nombre, ASIGNATURA.descripcion, ASIGNATURA.requerimientoAul, ASIGNATURA.departamento) AGAINST ('%s'IN BOOLEAN MODE))) AS puntuacion FROM (OFERTAR JOIN BLOQUE ON (OFERTAR.idBloque=BLOQUE.id ) ) JOIN ASIGNATURA ON (BLOQUE.idAsignatura=ASIGNATURA.id) WHERE (MATCH(OFERTAR.profesor) AGAINST ('%s' IN BOOLEAN MODE) or MATCH(BLOQUE.nombre) AGAINST ('%s'IN BOOLEAN MODE) or MATCH(ASIGNATURA.codigo, ASIGNATURA.nombre, ASIGNATURA.descripcion, ASIGNATURA.requerimientoAul, ASIGNATURA.departamento) AGAINST ('%s'IN BOOLEAN MODE)) ORDER BY puntuacion DESC  limit 0,20 ",$bus,$bus,$bus,$bus,$bus,$bus);
        } 
        return self::doQuery($query,"");
    }

      public static function BusquedaAvanzadaSaoa($bus,$t,$tabla,$rangoI=0,$rangoF=50){
        if ($tabla=="OFERTAR") {
            $query=sprintf("SELECT DISTINCT OFERTAR.*, ((MATCH( OFERTAR.profesor) AGAINST ('%s' IN BOOLEAN MODE))+(MATCH(BLOQUE.nombre) AGAINST ('%s'IN BOOLEAN MODE))+(MATCH(ASIGNATURA.codigo, ASIGNATURA.nombre, ASIGNATURA.descripcion, ASIGNATURA.requerimientoAul, ASIGNATURA.departamento) AGAINST ('%s'IN BOOLEAN MODE))) AS puntuacion FROM (OFERTAR JOIN BLOQUE ON (OFERTAR.idBloque=BLOQUE.id && OFERTAR.idOferta='%d') ) JOIN ASIGNATURA ON (BLOQUE.idAsignatura=ASIGNATURA.id) WHERE (MATCH(OFERTAR.profesor) AGAINST ('%s' IN BOOLEAN MODE) or MATCH(BLOQUE.nombre) AGAINST ('%s'IN BOOLEAN MODE) or MATCH(ASIGNATURA.codigo, ASIGNATURA.nombre, ASIGNATURA.descripcion, ASIGNATURA.requerimientoAul, ASIGNATURA.departamento) AGAINST ('%s'IN BOOLEAN MODE)) ORDER BY puntuacion DESC  limit 0,20 ",$bus,$bus,$bus,$t,$bus,$bus,$bus);
        }elseif ($tabla=="OFERTAFINAL") {
            $query=sprintf("SELECT DISTINCT OFERTAFINAL.*, ((MATCH( OFERTAFINAL.profesor) AGAINST ('%s' IN BOOLEAN MODE))+(MATCH(BLOQUE.nombre) AGAINST ('%s'IN BOOLEAN MODE))+(MATCH(ASIGNATURA.codigo, ASIGNATURA.nombre, ASIGNATURA.descripcion, ASIGNATURA.requerimientoAul, ASIGNATURA.departamento) AGAINST ('%s'IN BOOLEAN MODE))) AS puntuacion FROM (OFERTAFINAL JOIN BLOQUE ON (OFERTAFINAL.idBloque=BLOQUE.id && OFERTAFINAL.idOferta='%d') ) JOIN ASIGNATURA ON (BLOQUE.idAsignatura=ASIGNATURA.id) WHERE (MATCH(OFERTAFINAL.profesor) AGAINST ('%s' IN BOOLEAN MODE) or MATCH(BLOQUE.nombre) AGAINST ('%s'IN BOOLEAN MODE) or MATCH(ASIGNATURA.codigo, ASIGNATURA.nombre, ASIGNATURA.descripcion, ASIGNATURA.requerimientoAul, ASIGNATURA.departamento) AGAINST ('%s'IN BOOLEAN MODE)) ORDER BY puntuacion DESC  limit 0,20 ",$bus,$bus,$bus,$t,$bus,$bus,$bus);
        } else
            return False;
        return self::doQuery($query,"");
    }


	public static function obtenerManyToMany ($table, $from_field, $to_field, $search_id, $filtros_extra = array(), $in_objects=False, $class_name = '') {
	  $query = sprintf("SELECT %s FROM %s WHERE %s = %s", $to_field, $table, $from_field, $search_id);

	  // Chequeamos si hay filtros extra:
	  if (!empty($filtros_extra)) {
	    foreach ($filtros_extra as $key => $value) {
	      $query .= " AND " . $key . " = " . $value;
	    }
	  }

	  if (!$in_objects) {
	    $objs = self::doQuery($query);
	    $res = array();
	    if (!empty($objs)) {
	      foreach ($objs as $obj)
		$res[] = $obj->$to_field;
	    }
	    return $res;
	  }
	  else {}
	  // No se puede implementar con php 5.2.6...hay ke esperar a php 5.3
	}

	public static function raw_insert($table, $values) {
	  $attrs = ""; $vals = "";
	  foreach($values as $key => $value) {
	    $attrs .= $key . ",";
	    $vals  .= $value . ",";
	  }

	  $attrs = substr($attrs, 0, -1);
	  $vals  = substr($vals, 0, -1);

	  $query = sprintf("INSERT INTO %s (%s) VALUES (%s)", $table, $attrs, $vals);
	  return self::doQuery($query);
	}

}

